<?php
namespace dream;

class DreamChat{
	protected $master = null;//服务端
	protected $connectPool = [];//socket链接池
	protected $handPool = [];//http升级websocket池

	public function __construct($ip, $port){		       
	  $this->startServer($ip, $port);
	}

	public function startServer($ip, $port){
	  $this->connectPool[] = $this->master = \socket_create(AF_INET, SOCK_STREAM, SOL_TCP);//创建套接字链接 IP4  TCP流式套接字 指定协议TCP
	  \socket_bind($this->master, $ip, $port);//绑定套接字
	  \socket_listen($this->master, 1000);//创建监听  并发 同时链接人数
	  while(true){
	  	$sockets = $this->connectPool;
	    $write = $except = null;
	    \socket_select($sockets, $write, $except, 60);//阻塞链接 超时时间 如果没有链接进来暂时关闭
         
         foreach($sockets as $socket){
         	if($socket == $this->master){//判断是否是客户端
         		$this->connectPool[] = $client = \socket_accept($this->master);//接受客户端链接
         		$keyArr = \array_keys($this->connectPool, $client);
         		$key = end($keyArr);
         		$this->handPool[$key] = false;
         	}else{
         		$length = \socket_recv($socket, $buffer, 1024, 0);//接受socket数据
         		if($length < 1){//数据小于最小值时判断 客户端断开链接
         			$this->close($socket);
         		}else{
         			$key = \array_search($socket, $this->connectPool);
         			if($this->handPool[$key] == false){//判断是否握手
         				$this->handShake($socket, $buffer, $key);//握手方法
         			}else{
         				$message = $this->deFrame($buffer);
         				$message = $this->enFrame($message);
         				$this->send($message);
         			}
         		}
         	}
         }
	  }
	}



   //客户端断开链接
	public function close($socket){
		$key = \array_search($socket, $this->connectPool);
		unset($this->connectPool[$key]);
		unset($this->handPool[$key]);
		\socket_close($socket);
	}

	//http升级websocket
	public function handShake($socket, $buffer, $key){

         if(preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $buffer, $match)){//截取字符串
         	$responseKey = base64_encode(sha1($match[1]."258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));//将截取的key加密
            $upgrade = "HTTP/1.1 101 Switching Protocol\r\n" .
                       "Upgrade: websocket\r\n" .
                       "Connection: Upgrade\r\n" .
                       "Sec-WebSocket-Accept: ".$responseKey."\r\n\r\n";
            socket_write($socket, $upgrade, strlen($upgrade));//写入套接字缓冲区
            $this->handPool[$key] = true;//标记套接字握手成功
         }

	}

	//数据解帧
	public function deFrame($buffer){
		$len = $masks = $data = $decoded = null;
		$len = ord($buffer[1] & 127);

		if($len === 126){
			$masks = substr($buffer, 4, 4);
			$data = substr($buffer, 8);
		}elseif($len === 127){
			$masks =substr($buffer, 10, 4);
			$data = substr($buffer, 14);
		}else{
			$masks = substr($buffer, 2, 4);
			$data = substr($buffer, 6);
		}
		for($index = 0; $index < strlen($data);$index++){
			$decoded .=$data[$index] ^ $masks[$index % 4];
		}
		return $decoded;
	}

	//数据封帧
	public function enFrame($message){
		$len = strlen($message);
		if($len <= 125){
			return "\x81" .chr($len) . $message;
		}else if($len <= 65535){
			return "\x81" .chr(126) . pack("n", $len) . $message;
		}else{
			return "\x81" .chr(127) . pack("xxxxN", $len) . $message;
		}
    }
//群聊发给所有客户端
    public function send($message){
    	foreach($this->connectPool as $socket){
    		if($socket != $this->master){
    			socket_write($socket, $message, strlen($message));
    		}
    	}
    }

}